/**
 * @file GPS日志解析服务
 * @description 解析GPS日志数据，并调用坐标转换
 * @author Assistant
 * @date 2024-02-05
 * @updated 2024-03-09
 */

import { Injectable } from '@nestjs/common';
import { CoordinateService } from './coordinate.service';
import { LoggerService } from '../../../common/services/logger.service';
import { RawGpsLogData, GpsData, LbsData, PositionData } from '../interfaces/raw-gps-log-data.interface';
import { GpsLogData } from '../interfaces/gps-log-data.interface';
import { GpsLogRepository } from '../repositories/gps-log.repository';
import { GpsLogAdapter } from '../adapters/gps-log.adapter';
import { ApiResponse } from '../../common/dto/api-response.dto';
import { CoordinateFilterUtil } from '../utils/coordinate-filter.util';
import * as path from 'path';
import * as readline from 'readline';
import { createReadStream } from 'fs';
import {
  ProcessingStats,
  LineProcessingResult,
  BatchConfig,
  ProcessingTaskStatus,
  ProcessingTaskInfo,
  TaskProgressUpdate
} from '../interfaces/log-processing.interface';
import { DeviceListResponse } from '../interfaces/device.interface';
import { DeviceQueryDto } from '../dto/device-query.dto';

@Injectable()
export class GpsLogService {
  // 调整速度阈值
  private readonly MAX_SPEED = {
    HIGHWAY: 44.44,    // 高速公路最大速度 160km/h ≈ 44.44m/s
    URBAN: 27.78,      // 城市道路最大速度 100km/h ≈ 27.78m/s
    DEFAULT: 40.28     // 默认最大速度 145km/h ≈ 40.28m/s
  };
  
  private readonly MAX_DISTANCE_GPS = 5000;  // GPS最大距离跳变 5km
  private readonly MAX_DISTANCE_LBS = 1000;  // 基站定位最大距离跳变 1km
  private readonly MIN_TIME_INTERVAL = 1;    // 最小时间间隔 1s
  private readonly MAX_TIME_INTERVAL = 1800; // 最大时间间隔 30min
  private readonly PROGRESS_LOG_INTERVAL = 1000; // 日志处理进度输出间隔
  
  // 批处理配置
  private readonly batchConfig: BatchConfig = {
    batchSize: 1000,              // 每批处理1000条记录
    commitThreshold: 5000,        // 累积5000条记录后提交到数据库
    logProgressInterval: 1000     // 每处理1000行记录输出一次进度
  };

  // 处理任务管理
  private processingTasks: Map<string, ProcessingTaskInfo> = new Map();

  constructor(
    private readonly gpsLogRepository: GpsLogRepository,
    private readonly coordinateService: CoordinateService,
    private readonly logger: LoggerService,
    private readonly gpsLogAdapter: GpsLogAdapter,
    private readonly coordinateFilterUtil: CoordinateFilterUtil
  ) {}

  private deviceStates: Map<string, { lastTimestamp: number, slidingWindow: { lng: number, lat: number }[] }> = new Map();

  /**
   * 处理日志文件 - 流式处理优化版本
   * @param filePath 日志文件路径
   * @param deviceId 设备ID (可选，如果日志数据中不包含设备ID)
   * @returns 处理结果包含处理条数和任务ID
   */
  async processLogFile(filePath: string, deviceId?: string): Promise<ApiResponse<{ 
    processedCount: number; 
    filteredCount: number; 
    totalParsed: number;
    taskId: string;
  }>> {
    try {
      // 生成任务ID
      // const taskId = uuidv4(); // 先注释掉，等待安装依赖
      const taskId = `task_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
      
      // 获取文件绝对路径
      const absolutePath = path.resolve(process.cwd(), '..', filePath);
      this.logger.log('开始处理日志文件', 'LogProcessorService', { filePath: absolutePath, taskId });
      
      // 创建任务信息
      const taskInfo: ProcessingTaskInfo = {
        taskId,
        deviceId,
        filePath,
        status: ProcessingTaskStatus.QUEUED,
        progress: 0,
        stats: {
          totalLines: 0,
          parsedCount: 0,
          processedCount: 0,
          filteredCount: 0,
          errorCount: 0,
          startTime: Date.now(),
        },
        startTime: new Date(),
      };
      
      this.processingTasks.set(taskId, taskInfo);
      
      // 异步处理文件
      this.streamProcessFile(absolutePath, taskId, deviceId).then(stats => {
        // 更新任务信息
        const task = this.processingTasks.get(taskId);
        if (task) {
          task.status = ProcessingTaskStatus.COMPLETED;
          task.progress = 100;
          task.stats = stats;
          task.endTime = new Date();
          task.duplicatesFiltered = this.coordinateFilterUtil.getStats().duplicatesFound;
          
          // 记录处理完成信息
          this.logProcessCompleted(stats);
        }
      }).catch(error => {
        // 更新任务出错信息
        const task = this.processingTasks.get(taskId);
        if (task) {
          task.status = ProcessingTaskStatus.FAILED;
          task.error = error instanceof Error ? error.message : String(error);
          task.endTime = new Date();
          
          this.logger.error(
            '日志处理失败',
            error instanceof Error ? error.stack : String(error),
            'GpsLogService',
            { taskId, filePath }
          );
        }
      });
      
      // 立即返回任务ID，不等待处理完成
      return ApiResponse.success({
        processedCount: 0,
        filteredCount: 0,
        totalParsed: 0,
        taskId
      }, '日志处理任务已提交');
    } catch (error) {
      return this.handleProcessError(error, filePath);
    }
  }
  
  /**
   * 获取任务处理状态
   * @param taskId 任务ID
   * @returns 任务信息
   */
  getTaskStatus(taskId: string): ApiResponse<ProcessingTaskInfo> {
    const taskInfo = this.processingTasks.get(taskId);
    if (!taskInfo) {
      return ApiResponse.error(`未找到任务: ${taskId}`);
    }
    return ApiResponse.success(taskInfo, '获取任务状态成功');
  }
  
  /**
   * 获取任务列表
   * @param limit 限制返回数量
   * @returns 任务列表
   */
  getTaskList(limit = 20): ApiResponse<ProcessingTaskInfo[]> {
    // 按开始时间倒序排列，最新的任务排在前面
    const tasks = Array.from(this.processingTasks.values())
      .sort((a, b) => b.startTime.getTime() - a.startTime.getTime())
      .slice(0, limit);
    
    return ApiResponse.success(tasks, '获取任务列表成功');
  }
  
  /**
   * 获取坐标过滤统计信息
   * @returns 过滤器统计信息
   */
  getFilterStats(): ApiResponse<any> {
    return ApiResponse.success(this.coordinateFilterUtil.getStats(), '获取坐标过滤统计信息成功');
  }
  
  /**
   * 流式处理文件 - 使用Node.js的readline接口逐行读取文件
   * @param absoluteFilePath 文件的绝对路径
   * @param taskId 任务ID
   * @param deviceId 设备ID (可选，用于覆盖日志中的设备ID)
   * @returns 处理统计信息
   */
  private async streamProcessFile(absoluteFilePath: string, taskId: string, deviceId?: string): Promise<ProcessingStats> {
    // 创建文件读取流
    const fileStream = createReadStream(absoluteFilePath, { encoding: 'utf-8', highWaterMark: 64 * 1024 });
    
    // 创建readline接口进行逐行读取
    const rl = readline.createInterface({
      input: fileStream,
      crlfDelay: Infinity
    });
    
    // 更新任务状态
    const taskInfo = this.processingTasks.get(taskId);
    if (taskInfo) {
      taskInfo.status = ProcessingTaskStatus.PROCESSING;
    }
    
    // 初始化统计信息
    const stats: ProcessingStats = {
      totalLines: 0,
      parsedCount: 0,
      processedCount: 0,
      filteredCount: 0,
      errorCount: 0,
      startTime: Date.now(),
      filePath: absoluteFilePath,
      isSuccess: true
    };
    
    // 批处理相关变量
    let batch: GpsLogData[] = [];
    let batchStartTime = Date.now();
    
    // 在处理每行数据后更新任务进度
    let lastProgressUpdate = Date.now();
    
    // 定期更新进度
    const updateProgress = () => {
      const now = Date.now();
      if (now - lastProgressUpdate >= 1000) { // 每秒最多更新一次
        lastProgressUpdate = now;
        if (taskInfo) {
          // 如果有总行数，计算准确进度；否则设置为不确定状态(-1)
          const progress = stats.totalLines > 0 ? Math.floor((stats.totalLines / stats.totalLines) * 100) : -1;
          taskInfo.progress = progress > 0 ? progress : 0;
          taskInfo.stats = { ...stats };
        }
      }
    };
    
    // 逐行处理文件
    for await (const line of rl) {
      stats.totalLines++;
      
      // 跳过空行
      if (!line.trim()) continue;
      
      // 调用processLogLine并传入当前行号
      const result = await this.processLogLine(line, stats.totalLines);
      
      // 更新统计信息
      this.updateStats(stats, result);
      
      // 收集处理后的数据
      if (result.processedData) {
        batch.push(result.processedData);
        
        // 当批量达到提交阈值时，保存数据
        if (batch.length >= this.batchConfig.commitThreshold) {
          await this.saveProcessedBatch(batch);
          this.logger.log(`批量保存了${batch.length}条数据记录`, 'LogProcessorService');
          batch = []; // 清空批次
          batchStartTime = Date.now(); // 重置批次开始时间
        }
      }
      
      // 定期输出进度
      if (stats.totalLines % this.batchConfig.logProgressInterval === 0) {
        this.logProgress(stats);
      }
    }
    
    // 处理最后一批数据
    if (batch.length > 0) {
      await this.saveProcessedBatch(batch);
      this.logger.log(`保存最后一批${batch.length}条数据记录`, 'LogProcessorService');
    }
    
    // 更新最终统计
    stats.processedCount = stats.parsedCount;
    stats.endTime = Date.now();
    
    // 在完成处理后设置任务状态
    if (taskInfo) {
      taskInfo.progress = 100;
      taskInfo.stats = { ...stats };
    }

    return stats;
  }
  
  /**
   * 保存处理后的数据批次
   * @param batch 数据批次
   */
  private async saveProcessedBatch(batch: GpsLogData[]): Promise<void> {
    if (batch.length === 0) return;
    
    try {
      // 使用自动分片的批量保存方法
      await this.gpsLogRepository.bulkSave(batch);
    } catch (error) {
      this.logger.error(
        '批量保存数据失败',
        error instanceof Error ? error.stack : String(error),
        'LogProcessorService'
      );
      // 出错时不中断整个处理流程，继续处理其他数据
    }
  }
  
  /**
   * 记录处理进度
   * @param stats 统计信息
   */
  private logProgress(stats: ProcessingStats): void {
    this.logger.debug(
      '日志处理进度',
      'LogProcessorService',
      {
        processedLines: stats.totalLines,
        successCount: stats.processedCount,
        errorCount: stats.errorCount,
        filteredCount: stats.filteredCount,
        memoryUsage: this.getMemoryUsage()
      }
    );
  }
  
  /**
   * 获取当前内存使用情况
   * @returns 内存使用信息
   */
  private getMemoryUsage(): any {
    const memoryUsage = process.memoryUsage();
    return {
      rss: `${(memoryUsage.rss / 1024 / 1024).toFixed(2)} MB`,
      heapTotal: `${(memoryUsage.heapTotal / 1024 / 1024).toFixed(2)} MB`,
      heapUsed: `${(memoryUsage.heapUsed / 1024 / 1024).toFixed(2)} MB`,
      external: `${(memoryUsage.external / 1024 / 1024).toFixed(2)} MB`
    };
  }
  
  /**
   * 处理单行日志数据
   * @param line 日志行内容
   * @param lineNumber 当前行号
   * @returns 行处理结果
   */
  private async processLogLine(line: string, lineNumber: number): Promise<LineProcessingResult> {
    try {
      // 1. 解析日志行
      this.logger.debug('开始处理日志行', 'GpsLogService', {
        lineNumber,
        rawData: line
      });

      const rawData = await this.parseLog(line);
      if (!rawData) {
        return {
          isFiltered: true,
          status: 'error'
        };
      }

      // 2. 数据清洗和坐标预处理
      const cleanResult = await this.cleanAndProcessData(rawData);
      if (cleanResult.filtered) {
        this.logger.warn('数据被过滤', 'GpsLogService', {
          lineNumber,
          rawData,
          reason: cleanResult.reason
        });
        return {
          rawData,
          isFiltered: true,
          status: 'filtered'
        };
      }

      // 3. 数据转换
      const processedData = this.gpsLogAdapter.adapt(rawData);
      
      // 4. 记录处理成功的数据
      this.logger.debug('日志处理成功', 'GpsLogService', {
        lineNumber,
        rawData,
        processedData
      });
      
      return {
        rawData,
        processedData,
        isFiltered: false,
        status: 'success'
      };
    } catch (error) {
      const errMsg = error instanceof Error ? error.message : String(error) + ` (at line ${lineNumber})`;
      this.logger.error('GPS日志处理失败', errMsg, 'GpsLogService', {
        lineNumber,
        rawData: line,
        error: error instanceof Error ? {
          name: error.name,
          message: error.message,
          stack: error.stack
        } : String(error)
      });
      return {
        isFiltered: true,
        status: 'error',
        error: errMsg
      };
    }
  }

  /**
   * 是否为有效的LBS数据
   * @param lbs LBS数据
   * @returns 是否有效
   */
  private isValidLbsData(lbs: { lbslat: string; lbslng: string }): boolean {
    if (!lbs || typeof lbs !== 'object') {
      return false;
    }

    if (typeof lbs.lbslat !== 'string' || typeof lbs.lbslng !== 'string') {
      return false;
    }

    // 验证格式是否符合要求
    const lngRegex = /^-?\d+(\.\d+)?$/;
    const latRegex = /^-?\d+(\.\d+)?$/;

    // 首先检查格式是否符合数值字符串的要求
    if (!lngRegex.test(lbs.lbslat) || !latRegex.test(lbs.lbslng)) {
      return false;
    }
    
    // 转换为数值并进行范围验证
    const lng = parseFloat(lbs.lbslat);
    const lat = parseFloat(lbs.lbslng);
    
    // 检查是否为NaN或(0,0)坐标
    if (isNaN(lng) || isNaN(lat) || (lng === 0 && lat === 0)) {
      return false;
    }
    
    // 检查坐标范围
    if (lng < -180 || lng > 180 || lat < -90 || lat > 90) {
      return false;
    }

    return true;
  }

  /**
   * 验证必要字段
   * @param data 需要验证的数据
   * @returns 是否包含所有必要字段
   */
  private validateRequiredFields(data: RawGpsLogData): boolean {
    const missingFields: string[] = [];
    
    // 验证基本必要字段
    if (!data.imei) {
      missingFields.push('imei');
    }
    if (!data.datetime) {
      missingFields.push('datetime');
    }
    
    // 验证是否至少有位置数据
    let hasValidPosition = false;
    
    // 1. 检查position字段
    if (data.position && typeof data.position === 'object') {
      if (data.position.lng !== undefined && data.position.lat !== undefined) {
        hasValidPosition = true;
      }
    }
    
    // 2. 检查gps字段
    const hasGps = data.gps && Object.keys(data.gps).length > 0;
    if (hasGps && data.gps?.lng !== undefined && data.gps?.lat !== undefined) {
      hasValidPosition = true;
    }
    
    // 3. 检查lbs字段
    const hasLbs = data.lbs && Object.keys(data.lbs).length > 0;
    if (hasLbs && data.lbs?.lbslat && data.lbs?.lbslng) {
      hasValidPosition = true;
    }
    
    if (!hasValidPosition) {
      missingFields.push('有效的位置数据(position/gps/lbs)');
    }
    
    // 如果有GPS数据且包含坐标，验证坐标有效性
    if (hasGps && data.gps?.lng !== undefined && data.gps?.lat !== undefined) {
      // 验证GPS坐标类型
      if (typeof data.gps?.lng !== 'number') {
        missingFields.push('gps.lng必须是数值类型');
      }
      if (typeof data.gps?.lat !== 'number') {
        missingFields.push('gps.lat必须是数值类型');
      }
      
      // 验证GPS坐标范围
      if (typeof data.gps?.lng === 'number' && typeof data.gps?.lat === 'number') {
        if (data.gps.lng === 0 && data.gps.lat === 0) {
          missingFields.push('gps坐标无效(0,0)');
        }
        if (data.gps.lng < -180 || data.gps.lng > 180) {
          missingFields.push('gps.lng范围错误');
        }
        if (data.gps.lat < -90 || data.gps.lat > 90) {
          missingFields.push('gps.lat范围错误');
        }
      }
    }
    
    if (missingFields.length > 0) {
      throw new Error('数据验证失败: ' + missingFields.join(', '));
    }
    
    return true;
  }
  
  /**
   * 更新处理统计信息
   * @param stats 统计信息
   * @param result 行处理结果
   */
  private updateStats(stats: ProcessingStats, result: LineProcessingResult): void {
    if (result.rawData) {
      stats.parsedCount++;
    }
    
    switch (result.status) {
      case 'success':
        stats.processedCount++;
        break;
      case 'filtered':
        stats.filteredCount++;
        break;
      case 'error':
        stats.errorCount++;
        break;
    }
  }
  
  /**
   * 记录处理完成信息
   * @param stats 统计信息
   */
  private logProcessCompleted(stats: ProcessingStats): void {
    this.logger.log(
      '日志文件处理完成',
      'LogProcessorService',
      {
        totalLines: stats.totalLines,
        parsedCount: stats.parsedCount,
        processedCount: stats.processedCount,
        errorCount: stats.errorCount,
        filteredCount: stats.filteredCount,
        memoryUsage: this.getMemoryUsage()
      }
    );
  }
  
  /**
   * 处理处理过程中的错误
   * @param error 错误对象
   * @param filePath 文件路径
   * @returns API错误响应
   */
  private handleProcessError(error: unknown, filePath: string): ApiResponse<any> {
    this.logger.error(
      '日志文件处理失败',
      error instanceof Error ? error.stack : String(error),
      'LogProcessorService',
      { filePath }
    );
    return ApiResponse.error(
      '日志文件处理失败: ' + (error instanceof Error ? error.message : String(error))
    );
  }
  
  /**
   * 解析GPS日志行数据
   * @param logLine 日志行数据
   * @returns 解析后的GPS数据
   */
  private async parseLog(line: string): Promise<RawGpsLogData> {
    try {
      const rawData = JSON.parse(line);
      this.validateRequiredFields(rawData);
      return rawData;
    } catch (error) {
      const errorMessage = `GPS日志解析失败: ${error instanceof Error ? error.message : '未知错误'}`;
      // 不在这里记录错误日志，统一在上层处理
      throw new Error(errorMessage);
    }
  }

  /**
   * 清洗和处理原始数据
   * @param rawData 原始GPS日志数据
   * @returns 清洗结果
   */
  private async cleanAndProcessData(rawData: RawGpsLogData): Promise<{ filtered: boolean; reason?: string }> {
    try {
      // 1. 验证必要字段
      if (!this.validateRequiredFields(rawData)) {
        return { filtered: true, reason: '缺少必要字段' };
      }

      // 2. 检查位置数据的优先级
      // 优先使用position字段
      if (rawData.position && rawData.position.lng !== undefined && rawData.position.lat !== undefined) {
        // position字段已存在且有效，不需要额外处理
        return { filtered: false };
      }

      // 3. 检查GPS数据是否有效
      const hasValidGps = rawData.gps && 
                         rawData.gps?.lng !== undefined && 
                         rawData.gps?.lat !== undefined && 
                         typeof rawData.gps?.lng === 'number' && 
                         typeof rawData.gps?.lat === 'number' &&
                         !(rawData.gps.lng === 0 && rawData.gps.lat === 0);
      
      // 4. 检查LBS数据是否有效
      const hasValidLbs = rawData.lbs && this.isValidLbsData(rawData.lbs);
      
      // 5. 处理位置数据 - 优先使用GPS数据，如果GPS数据无效则使用LBS数据
      if (hasValidGps && rawData.gps) {
        // 保存原始GPS数据
        rawData.originalPosition = { 
          lng: rawData.gps.lng as number, 
          lat: rawData.gps.lat as number 
        };
        
        // 先进行坐标系转换
        const convertedCoord = await this.coordinateService.convertCoordinates(
          rawData.gps.lng as number,
          rawData.gps.lat as number,
          1, // WGS84
          5  // BD09
        );
        
        // 对转换后的坐标进行预处理
        const preprocessResult = this.preprocessCoordinate(
          rawData.imei,
          convertedCoord,
          rawData.datetime,
          rawData.gps.speed || 0,
          'gps'
        );
        
        if (preprocessResult === null) {
          // GPS坐标异常，尝试使用LBS数据
          if (hasValidLbs) {
            this.logger.warn('GPS坐标异常，尝试使用LBS数据', 'LogProcessorService', { 
              deviceId: rawData.imei, 
              datetime: rawData.datetime 
            });
            return this.processLbsData(rawData);
          }
          return { filtered: true, reason: 'GPS坐标异常且无有效LBS数据' };
        }
        
        // 更新坐标为预处理后的结果
        rawData.position = {
          lng: preprocessResult.lng,
          lat: preprocessResult.lat,
          source: 'gps',
          isFix: rawData.gps.isFix || false,
          speed: rawData.gps.speed || 0
        };
        
        return { filtered: false };
      } else if (hasValidLbs) {
        // GPS数据无效，使用LBS数据
        return this.processLbsData(rawData);
      } else {
        return { filtered: true, reason: '无有效的位置数据' };
      }
    } catch (error) {
      const errorMsg = error instanceof Error ? error.stack : String(error);
      this.logger.error('数据清洗处理失败', errorMsg, 'LogProcessorService', { rawData });
      return { filtered: true, reason: '数据清洗处理过程中出错' };
    }
  }
  
  /**
   * 处理LBS数据
   * @param rawData 原始GPS日志数据
   * @returns 处理结果
   */
  private async processLbsData(rawData: RawGpsLogData): Promise<{ filtered: boolean; reason?: string }> {
    try {
      // 添加调试日志：输出初始LBS数据
      this.logger.debug('开始处理LBS数据', 'GpsLogService', {
        deviceId: rawData.imei,
        lbs: rawData.lbs
      });
      
      if (!rawData.lbs || !this.isValidLbsData(rawData.lbs)) {
        return { filtered: true, reason: 'LBS数据无效' };
      }
      
      // LBS坐标需要转换为数值类型
      // 注意：字段名称与实际含义不一致
      // lbslat 实际存储的是经度值，lbslng 实际存储的是纬度值
      const lbsLng = parseFloat(rawData.lbs.lbslat); // 从lbslat字段获取经度
      const lbsLat = parseFloat(rawData.lbs.lbslng); // 从lbslng字段获取纬度
      
      // 添加调试日志：输出解析后的LBS坐标
      this.logger.debug('解析LBS坐标', 'GpsLogService', {
        deviceId: rawData.imei,
        lbsLng,
        lbsLat
      });
      
      // 检查坐标是否为NaN或(0,0)，与GPS数据处理保持一致
      if (isNaN(lbsLng) || isNaN(lbsLat) || (lbsLng === 0 && lbsLat === 0)) {
        return { filtered: true, reason: 'LBS坐标格式无效或为(0,0)' };
      }
      
      // 验证坐标范围是否合理，与GPS数据处理保持一致
      if (lbsLng < -180 || lbsLng > 180 || lbsLat < -90 || lbsLat > 90) {
        return { filtered: true, reason: 'LBS坐标范围错误' };
      }
      
      // 保存原始LBS数据
      rawData.originalPosition = { lng: lbsLng, lat: lbsLat };
      
      // 先进行坐标系转换
      const convertedCoord = await this.coordinateService.convertCoordinates(
        lbsLng,
        lbsLat,
        1, // WGS84
        5  // BD09
      );
      
      // 添加调试日志：输出坐标转换结果
      this.logger.debug('坐标转换结果', 'GpsLogService', {
        deviceId: rawData.imei,
        original: { lng: lbsLng, lat: lbsLat },
        converted: convertedCoord
      });
      
      // 对转换后的坐标进行预处理
      const preprocessResult = this.preprocessCoordinate(
        rawData.imei,
        convertedCoord,
        rawData.datetime,
        0, // LBS没有速度信息
        'lbs'
      );
      
      // 添加调试日志：输出预处理结果
      this.logger.debug('坐标预处理结果', 'GpsLogService', {
        deviceId: rawData.imei,
        preprocessResult
      });
      
      if (preprocessResult === null) {
        return { filtered: true, reason: 'LBS坐标异常' };
      }
      
      // 不直接修改原始数据的lbs字段，而是设置position字段
      rawData.position = {
        lng: preprocessResult.lng,
        lat: preprocessResult.lat,
        source: 'lbs',
        isFix: true,
        speed: 0
      };
      
      return { filtered: false };
    } catch (error) {
      const errorMsg = error instanceof Error ? error.stack : String(error);
      this.logger.error('LBS坐标处理失败', errorMsg, 'LogProcessorService', { rawData });
      return { filtered: true, reason: 'LBS坐标处理失败' };
    }
  }

  /**
   * 处理位置数据
   * @param rawData 原始GPS数据
   * @returns 处理后的位置数据
   */
  async processPositionData(rawData: RawGpsLogData): Promise<{
    position?: { lng: number; lat: number };
    original?: { lng: number; lat: number };
    positionSource?: 'gps' | 'lbs' | null;
    speed: number;
    positionValid: boolean;
  }> {
    let positionData = {
      speed: 0,
      positionValid: false,
      positionSource: null as 'gps' | 'lbs' | null
    };

    // 首先检查是否已经有处理好的position字段
    if (rawData.position && rawData.position.lng !== undefined && rawData.position.lat !== undefined) {
      this.logger.debug(`使用已处理的位置数据`, 'GpsLogService', {
        deviceId: rawData.imei,
        source: rawData.position.source.toUpperCase(),
        accuracy: rawData.position.source === 'gps' ? 'GPS定位精度通常在10米以内' : '基站定位精度通常在100-1000米'
      });

      return {
        position: { 
          lng: rawData.position.lng,
          lat: rawData.position.lat
        },
        original: rawData.originalPosition || { 
          lng: rawData.position.lng, 
          lat: rawData.position.lat 
        },
        positionSource: rawData.position.source,
        speed: rawData.position.speed || 0,
        positionValid: true
      };
    }

    // 检查GPS数据是否有效
    const hasValidGps = rawData.gps && 
                       rawData.gps.lng !== undefined && 
                       rawData.gps.lat !== undefined && 
                       typeof rawData.gps.lng === 'number' && 
                       typeof rawData.gps.lat === 'number';

    // 检查是否有有效的位置数据
    if (hasValidGps && this.validateRequiredFields(rawData) && rawData.gps) {
      // 使用已经转换和预处理过的坐标
      return {
        position: { 
          lng: rawData.gps.lng as number, 
          lat: rawData.gps.lat as number 
        },
        original: rawData.originalPosition || { 
          lng: rawData.gps.lng as number, 
          lat: rawData.gps.lat as number 
        },
        positionSource: 'gps', // 根据新的接口定义，gps已没有source属性
        speed: rawData.gps.speed || 0,
        positionValid: true
      };
    }

    return positionData;
  }

  /**
   * 预处理坐标
   * 检查坐标异常、过滤异常点、平滑轨迹
   * @param deviceId 设备ID
   * @param current 当前坐标
   * @param timestamp 时间戳
   * @param reportedSpeed 上报的速度
   * @param source 定位来源
   * @returns 平滑后的坐标，若检测到异常则返回null
   */
  private preprocessCoordinate(deviceId: string, current: { lng: number, lat: number }, timestamp: string, reportedSpeed: number, source: 'gps' | 'lbs' | null): { lng: number, lat: number } | null {
    try {
      // 参数验证和日志
      this.logger.debug('坐标预处理开始', 'GpsLogService', {
        deviceId,
        current,
        timestamp,
        reportedSpeed,
        source
      });
      
      // 检查输入是否有效
      if (!current || typeof current.lng !== 'number' || typeof current.lat !== 'number') {
        this.logger.warn('坐标预处理失败：无效的坐标数据', 'GpsLogService', { deviceId, current });
        return null;
      }
      
      // 格式化时间
      let currentTime: number;
      try {
        currentTime = new Date(timestamp).getTime();
        if (isNaN(currentTime)) {
          this.logger.warn('坐标预处理失败：无效的时间戳', 'GpsLogService', { deviceId, timestamp });
          // 使用当前时间作为默认值
          currentTime = Date.now();
        }
      } catch (error) {
        this.logger.warn('坐标预处理时间戳解析失败', 'GpsLogService', { deviceId, timestamp, error });
        currentTime = Date.now();
      }
      
      const windowSize = 5;
      
      // 1. 检查是否为重复坐标（使用布隆过滤器）
      try {
        if (this.coordinateFilterUtil.hasCoordinate(deviceId, current.lng, current.lat)) {
          this.logger.warn(
            `过滤重复坐标: 设备 ${deviceId} 坐标(${current.lng.toFixed(6)}, ${current.lat.toFixed(6)})`,
            'GpsLogService'
          );
          return null;
        }
      } catch (error) {
        // 如果过滤器出错，记录但继续处理
        this.logger.error(
          '坐标重复检查失败', 
          error instanceof Error ? error.message : String(error),
          'GpsLogService', 
          { deviceId, current }
        );
        // 出错时不过滤，允许继续处理
      }
      
      // 初始化设备状态
      if (!this.deviceStates.has(deviceId)) {
        this.deviceStates.set(deviceId, { lastTimestamp: currentTime, slidingWindow: [current] });
        // 将首个坐标添加到过滤器
        try {
          this.coordinateFilterUtil.addCoordinate(deviceId, current.lng, current.lat);
        } catch (error) {
          this.logger.error(
            '添加坐标到过滤器失败', 
            error instanceof Error ? error.message : String(error),
            'GpsLogService', 
            { deviceId, current }
          );
          // 继续处理，不中断流程
        }
        return current;
      }

      const state = this.deviceStates.get(deviceId)!;
      let dt = (currentTime - state.lastTimestamp) / 1000;  // 转换为秒

      // 2. 时间间隔检查
      if (dt < this.MIN_TIME_INTERVAL) {
        dt = this.MIN_TIME_INTERVAL;  // 防止除零
      } else if (dt > this.MAX_TIME_INTERVAL) {
        this.logger.warn(`设备 ${deviceId} 时间间隔过大: ${(dt/60).toFixed(1)}分钟，开始新的轨迹段`, 'GpsLogService');
        state.slidingWindow = [current];
        state.lastTimestamp = currentTime;
        try {
          this.coordinateFilterUtil.resetDeviceFilter(deviceId); // 重置该设备的过滤器
          this.coordinateFilterUtil.addCoordinate(deviceId, current.lng, current.lat);
        } catch (error) {
          this.logger.error(
            '重置过滤器失败', 
            error instanceof Error ? error.message : String(error),
            'GpsLogService', 
            { deviceId }
          );
          // 继续处理，不中断流程
        }
        return current;
      }

      // 更新设备状态
      state.lastTimestamp = currentTime;
      try {
        this.coordinateFilterUtil.addCoordinate(deviceId, current.lng, current.lat);
      } catch (error) {
        this.logger.error(
          '添加坐标到过滤器失败', 
          error instanceof Error ? error.message : String(error),
          'GpsLogService', 
          { deviceId, current }
        );
      }
      
      // 更新滑动窗口
      state.slidingWindow.push(current);
      if (state.slidingWindow.length > windowSize) {
        state.slidingWindow.shift();
      }

      return current;
    } catch (error) {
      this.logger.error(
        '坐标预处理过程发生错误', 
        error instanceof Error ? error.stack : String(error),
        'GpsLogService', 
        { deviceId, current, timestamp }
      );
      return null;
    }
  }

  /**
   * 使用Haversine公式计算两个经纬度坐标之间的距离（单位：米）
   * @param p1 第一个坐标
   * @param p2 第二个坐标
   * @returns 两坐标间距离
   */
  private haversineDistance(p1: { lng: number, lat: number }, p2: { lng: number, lat: number }): number {
    const R = 6371000;
    const rad = Math.PI / 180;
    const dLat = (p2.lat - p1.lat) * rad;
    const dLng = (p2.lng - p1.lng) * rad;
    const a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(p1.lat * rad) * Math.cos(p2.lat * rad) * Math.sin(dLng/2) * Math.sin(dLng/2);
    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    return R * c;
  }

  /**
   * 批量处理GPS日志数据，将原始数据进行处理转换后存储
   * @param dataList 处理后的GPS日志数据列表
   */
  async bulkProcessLogData(dataList: GpsLogData[]): Promise<ApiResponse<{ count: number }>> {
    try {
      await this.gpsLogRepository.bulkSave(dataList);
      return ApiResponse.success({ count: dataList.length }, '数据批量保存成功');
    } catch (error) {
      this.logger.error(
        '批量保存GPS日志数据失败',
        error instanceof Error ? error.stack : String(error),
        'GpsLogService'
      );
      return ApiResponse.error(
        '批量保存GPS日志数据失败: ' + (error instanceof Error ? error.message : String(error))
      );
    }
  }

  /**
   * 根据设备ID查询GPS日志数据
   * @param deviceId 设备ID
   * @param filters 过滤条件
   * @returns GPS日志数据列表
   */
  async findByDeviceId(deviceId: string, filters?: {
    startTime?: Date;
    endTime?: Date;
  }): Promise<ApiResponse<{ count: number, tracks: any[] }>> {
    try {
      // 使用新方法获取已排序的轨迹数据
      const data = await this.gpsLogRepository.getDeviceTrack(deviceId, filters);
      
      return ApiResponse.success({
        count: data.length,
        tracks: data
      }, `成功获取设备${deviceId}的轨迹数据`);
    } catch (error) {
      this.logger.error(
        `查询设备${deviceId}的轨迹数据失败`,
        error instanceof Error ? error.stack : String(error),
        'GpsLogService'
      );
      return ApiResponse.error(
        `查询设备${deviceId}的轨迹数据失败: ` + (error instanceof Error ? error.message : String(error))
      );
    }
  }

  /**
   * 根据设备ID分页查询记录 
   * @param deviceId 设备ID
   * @param page 页码
   * @param limit 每页条数
   * @returns 分页查询结果
   */
  async findByDeviceIdPaged(
    deviceId: string,
    page: number = 1,
    limit: number = 100
  ): Promise<ApiResponse<{ total: number; page: number; limit: number; records: any[] }>> {
    try {
      // 使用新方法获取已排序的轨迹分页数据
      const result = await this.gpsLogRepository.getDeviceTrackPaged(deviceId, page, limit);
      
      return ApiResponse.success({
        total: result.total,
        page: result.page,
        limit,
        records: result.data
      }, `成功获取设备${deviceId}的轨迹数据`);
    } catch (error) {
      this.logger.error(
        '分页查询GPS日志数据失败',
        error instanceof Error ? error.stack : String(error),
        'GpsLogService'
      );
      return ApiResponse.error(
        '分页查询GPS日志数据失败: ' + (error instanceof Error ? error.message : String(error))
      );
    }
  }

  /**
   * 获取所有设备ID列表
   * @param queryDto 查询参数
   * @returns 设备列表响应
   */
  async getAllDeviceIdsList(queryDto: DeviceQueryDto): Promise<ApiResponse<DeviceListResponse>> {
    try {
      const deviceIdList = await this.gpsLogRepository.getAllDeviceIdsList(queryDto);
      return deviceIdList;
    } catch (error) {
      this.logger.error('获取设备ID列表失败', error instanceof Error ? error.stack : String(error), 'GpsLogService');
      return ApiResponse.error('获取设备ID列表失败');
    }
  }
} 